/*
    作者：zx
    时间：2022.11.13
    描述：任务结构体初始化和tss初始化
*/

#include "core/task.h"
#include "tools/klib.h"
#include "os_cfg.h"
#include "cpu/cpu.h"
#include "tools/log.h"
#include "comm/cpu_instr.h"
#include "cpu/irq.h"
#include "core/memory.h"
#include "cpu/mmu.h"
#include "core/syscall.h"
#include "comm/elf.h"
#include "fs/fs.h"

static task_manager_t task_manager;
static uint32_t idel_task_stack[OS_IDEL_TASK_STACK_SIZE];
static task_t task_table[OS_TASK_MAX_NUM];
static mutex_t task_table_mutex;

// 从task table的选择新进程运行
static task_t * alloc_task(void)
{
    task_t * new_task = 0;
    mutex_lock(&task_table_mutex);
    for(int i=0;i<OS_TASK_MAX_NUM;i++)
    {
        task_t * curr = task_table + i;
        if(curr->name[0] == '\0')
        {
            new_task = curr;
        } 
    }
    mutex_unlock(&task_table_mutex);
    return new_task;
}

// 从task table中释放新进程
static void free_task(task_t * task)
{
    mutex_lock(&task_table_mutex);
    task->name[0] = '\0';
    mutex_unlock(&task_table_mutex);
}


// 
static int tss_init(task_t * task, uint32_t entry, uint32_t esp, int access)
{
    // 寻找空闲gdt表项
    int gdt_tss_selector = gdt_alloc_desc();
    if(gdt_tss_selector < 0)
    {
        log_printf("alloc gdt for tss failed!\n");
        return -1;
    }

    // 将该项任务的tss放入gdt表，
    segment_desc_set(gdt_tss_selector, (uint32_t)&task->tss, sizeof(task->tss),
        SEG_P_PRESENT | SEG_DPL0 | SEG_TYPE_TSS
    );
    // tss清零
    kernel_memset(&task->tss, 0, sizeof(task->tss));

    int code_selector, data_selector;
    if(access & TASK_TYPE_SYSTEM)
    {
        code_selector = KERNEL_SELECTOR_CS;
        data_selector = KERNEL_SELECTOR_DS;
    }
    else
    {
        code_selector = task_manager.task_code_selector | SEG_CPL3;
        data_selector = task_manager.task_data_selector | SEG_CPL3;
    }

    // 进程需要两个栈，一个是自身运行所需栈，一个是发生中断/异常/系统调用所需栈
    // 此处为进程分配内核栈
    uint32_t task_stack_when_kernel = memory_alloc_page();
    if(task_stack_when_kernel < 0)
    {
        log_printf("alloc kernel stack for task failed!");
        goto tss_init_failed;
    }

    // eip指向进程入口
    task->tss.eip = entry;
    // 这里都是特权级为0的系统栈,栈顶指针为[1024]的地址
    task->tss.esp = esp;
    task->tss.esp0 = task_stack_when_kernel + MEMORY_PAGE_SIZE;
    // 内核数据段选择子
    task->tss.ss = data_selector;
    task->tss.ss0 = KERNEL_SELECTOR_DS;
    task->tss.ds = task->tss.es = task->tss.fs = task->tss.gs = data_selector;
    // 内核代码段选择子
    task->tss.cs = code_selector;
    // eflags寄存器设置
    task->tss.eflags = EFLAGS_ALWAYS_1 | EFLAGS_IF; 

    // 为进程分配进程页表
    uint32_t task_page_dir = memory_create_user_linear_mem();
    if(!task_page_dir)
    {
        goto tss_init_failed;
    }
    task->tss.cr3 = task_page_dir;
    // 保存gdt选择子
    task->gdt_tss_selector = gdt_tss_selector;

    return 0;
tss_init_failed:
    // 分配失败，释放选择子
    gdt_free_selector(gdt_tss_selector);
    if(task_stack_when_kernel) memory_free_page(task_stack_when_kernel);
}

// 任务就绪
void task_start(task_t * task)
{
    irq_status_t status = irq_enter_protection();
    task_set_to_ready(task); 
    irq_quit_protection(status);
}
    

int init_task(task_t * task, const char * name, uint32_t entry, uint32_t esp, int access)
{
    // task不为空
    ASSERT(task != (task_t*)0);

    task->pid = (uint32_t)task;
    task->parent = 0;

    // 任务名
    kernel_strcpy(task->name, name);
    task->heap_start = task->heap_end = 0;
    task->time_ticks = task->slice_ticks = TASK_TIME_SLICE_COUNT_DEFAULT;
    task->sleep_ticks = 0;
    task->running_status = 0;
    // 使用tss绑定进程
    tss_init(task, entry, esp, access);

    // 节点初始化
    list_node_init(&task->all_node);
    list_node_init(&task->run_node);
    list_node_init(&task->wait_node);
    // 进程打开文件表初始化
    kernel_memset(task->file_table, 0, sizeof(task->file_table));
    // 创建完成 状态为创建态
    task->status = TASK_CREATED;

    irq_status_t irq_status = irq_enter_protection();
    // 任务节点插入任务队列
    list_insert_last(&task_manager.task_list, &task->all_node);
    irq_quit_protection(irq_status);

    // // 32位整数 变为 32位地址
    // uint32_t * pesp = (uint32_t*)esp;
    // if(pesp)
    // {
    //     // 程序入口地址入栈
    //     *(--pesp) = entry;
    //     // 四个0入栈，以便第一次simple_switch四个寄存器出栈
    //     for(int i = 0;i < 4;i++) *(--pesp) = 0;
    //     // task结构体中的栈为此时的栈顶指针
    //     task->stack = pesp;
    // }

    return 0;    
}

void task_uninit(task_t * task)
{
    if(task->gdt_tss_selector)
    {
        gdt_alloc_desc(gdt_free_selector(task->gdt_tss_selector));
    }

    if(task->tss.esp0)
    {
        memory_free_page(task->tss.esp0 - MEMORY_PAGE_SIZE);
    }

    if(task->tss.cr3)
    {
        memory_free_user_linear_mem(task->tss.cr3);
    }

    kernel_memset(task, 0, sizeof(task));
}

void task_manager_init(void)
{
    kernel_memset(task_table, 0, sizeof(task_table));
    mutex_init(&task_table_mutex);

    // 分配进程使用的数据段 段选择子
    // 代表需要请求的资源段
    int data_selector = gdt_alloc_desc();
    if(data_selector < 0)
    {   
        log_printf("no selector for data segment! task manager init failed!");
        return;
    }
    segment_desc_set(data_selector, 0, 0xFFFFFFFF, 
        SEG_P_PRESENT | SEG_DPL3 | SEG_S_NORMAL | SEG_TYPE_DATA | SEG_TYPE_RW | SEG_D);
    task_manager.task_data_selector = data_selector;

    // 分配用户进程使用的代码段 段选择子
    int code_selector = gdt_alloc_desc();
    if(code_selector < 0)
    {
        log_printf("no selector for code segment! task manager init failed!");
        return;
    }
    segment_desc_set(code_selector, 0, 0xFFFFFFFF, 
        SEG_P_PRESENT | SEG_DPL3 | SEG_S_NORMAL | SEG_TYPE_CODE | SEG_TYPE_RW | SEG_D);
    task_manager.task_code_selector = code_selector;

    list_init(&task_manager.ready_list);
    list_init(&task_manager.task_list);
    list_init(&task_manager.sleep_list);
    task_manager.curr_task = 0;
    init_task(
        &task_manager.idel_task, 
        "no ready task", 
        (uint32_t)idel_task_entry, 
        (uint32_t)(idel_task_stack + OS_IDEL_TASK_STACK_SIZE),
        TASK_TYPE_SYSTEM
    );
    task_start(&task_manager.idel_task);
}

// 空闲进程执行代码
void idel_task_entry(void)
{
    for(;;)
    {
        hlt();
    }
}

task_t * first_task_get(void)
{
    return &task_manager.first_task;
}

// 获取当前任务的结构体指针
task_t * curr_task_get(void)
{
    return task_manager.curr_task;
}

// 下一个需要运行的任务
task_t * task_next_run(void)
{
    if(list_count(&task_manager.ready_list)==0)
    {
        return &task_manager.idel_task;
    }
    // 从就绪队列中拿出第一个节点，并返回该节点对应的任务
    list_node_t * task_run_node = list_first(&task_manager.ready_list);
    return list_node_parent(task_run_node, task_t, run_node);
}


void first_task_init(void)
{
    // 导入lds文件中first task的物理内存地址，复制进
    extern uint8_t first_task_start_physical_addr[], first_task_end_physical_addr[]; 
    uint32_t copy_size = (uint32_t)(first_task_end_physical_addr - first_task_start_physical_addr);
    // 设置整个first task所占空间
    // 除开text bss data rodata大小，还要程序运行时所需的其他空间，如：栈
    uint32_t alloc_size = 10 * MEMORY_PAGE_SIZE;
    ASSERT(copy_size <= alloc_size);

    void first_task_entry(void);
    uint32_t first_task_entry_addr = (uint32_t)first_task_entry;
    // 初始化第一个任务（当前运行的程序）的任务结构体
    init_task(&task_manager.first_task, 
            "The first task!", 
            first_task_entry_addr, 
            first_task_entry_addr + alloc_size, 
            TASK_TYPE_USER);
    task_manager.first_task.heap_start = (uint32_t)first_task_end_physical_addr;
    task_manager.first_task.heap_end   = task_manager.first_task.heap_start;
    // 将目前运行的主程序写入任务寄存器 
    write_tr(task_manager.first_task.gdt_tss_selector); 
    task_manager.curr_task = &task_manager.first_task;

    // 将当前页表设置为进程持有的页表
    mmu_set_page_dir(task_manager.first_task.tss.cr3);

    // 为first task分配空间
    memory_alloc_page_for(first_task_entry_addr, alloc_size, PTE_P | PTE_W | PTE_U);
    kernel_memcpy((void *)first_task_entry_addr, first_task_start_physical_addr, copy_size);

    task_start(&task_manager.first_task);
}

// 插入就绪队列 设置状态为就绪状态
void task_set_to_ready(task_t * task)
{
    if(task == &task_manager.idel_task)
    {
        return ;
    }
    // 任务节点插入就绪队列
    list_insert_last(&task_manager.ready_list, &task->run_node);
    // 就绪完成 状态为就绪态
    task->status = TASK_READY;
}

// 从就绪队列取出任务
void task_remove_ready(task_t * task)
{
    if(task == &task_manager.idel_task)
    {
        return ;
    }
    list_remove_node(&task_manager.ready_list, &task->run_node);
}

// 任务切换 
void task_switch(task_t * from, task_t * to)
{
    // 使用tss切换进程
    switch_to_tss(to->gdt_tss_selector);
    // // 手动简单的切换进程栈
    // simple_switch(&from->stack, to->stack);
}

// 进程主动放弃cpu
int sys_yield(void)
{
    irq_status_t irq_status = irq_enter_protection();
    if(list_count(&task_manager.ready_list) > 1)
    {
        task_t * curr_task =  curr_task_get();
        // 就绪队列头部正在运行的进程放到尾部 等待cpu
        task_remove_ready(curr_task);
        task_set_to_ready(curr_task);
        task_manager_update();
    }
    irq_quit_protection(irq_status);
}

// 任务管理器更新，改变任务的状态、当前任务指向
void task_manager_update(void)
{
    irq_status_t irq_status = irq_enter_protection();
    task_t * to = task_next_run();
    if(to != task_manager.curr_task)
    {
        task_t * from = curr_task_get();
        task_manager.curr_task = to;
        task_switch(from, to);
    } 
    irq_quit_protection(irq_status);
}

// 程序时间片计数器更新
void task_time_ticks(void)
{
    task_t * curr_task = curr_task_get();

    // 如果当前为空闲任务，检查是否有就绪任务，有则运行就绪任务
    if(curr_task == &task_manager.idel_task && list_count(&task_manager.ready_list)>0)
    {
        task_manager_update();
    }
    
    // 当前为正常任务，检查当前任务时间片是否用完
    else if(curr_task != &task_manager.idel_task && --curr_task->slice_ticks <= 0) 
    {
        // 就绪队列头部正在运行的进程放到尾部 等待cpu
        task_remove_ready(curr_task);
        task_set_to_ready(curr_task);
        task_manager_update();
    }
    
    // 休眠队列检查
    list_node_t * task_run_node = list_first(&task_manager.sleep_list);
    while(task_run_node)
    {
        task_t * task = list_node_parent(task_run_node, task_t, run_node);
        // 这里不能写在后面，如果休眠时间到了，指针就从休眠列表中移除了
        // 不能正常p = p->next; 所以需要先保存
        task_run_node = list_node_next(task_run_node);
        if(--task->sleep_ticks <= 0)
        {
            task_set_to_wakeup(task);
            task_set_to_ready(task);
        }
    }
}

// 设置任务休眠
void task_set_to_sleep(task_t * task, uint32_t tick)
{
    if(!tick)
    {
        return ;
    }

    if(task == &task_manager.idel_task)
    {
        return ;
    }

    task->sleep_ticks = tick;
    task->status = TASK_SLEEP;
    list_insert_last(&task_manager.sleep_list, &task->run_node);
}

// 任务唤醒,从睡眠队列中取出任务
void task_set_to_wakeup(task_t * task)
{
    list_remove_node(&task_manager.sleep_list,&task->run_node);
}


// ---------------------------- 系统调用
// 让进程休眠ms毫秒
void sys_sleep(uint32_t ms)
{
    irq_status_t irq_status = irq_enter_protection();
    task_remove_ready(task_manager.curr_task);
    task_set_to_sleep(task_manager.curr_task, (ms+OS_TICKS_MS-1) / OS_TICKS_MS);
    task_manager_update();
    irq_quit_protection(irq_status);
}

int sys_getpid(void)
{
    return curr_task_get()->pid;
}

// 子进程复制父进程的文件打开表
static void copy_opened_file(task_t * child)
{
    task_t * parent = curr_task_get();
    for(int i=0; i<TASK_OPEN_FILE_MAX; i++)
    {
        file_t * file = parent->file_table[i];
        if(file)
        {
            file_inc_ref(file);
            child->file_table[i] = file;
        } 
    }
}

int sys_fork(void)
{
    task_t * parent_task = curr_task_get();
    task_t * child_task = alloc_task();
    if(!child_task)
    {
        goto fork_failed;
    }

    // 系统调用时，父进程的ss0栈中压入了参数    
    // 栈栈底开始 SS ESP id arg3-arg0 cs eip 
    // 和一部分寄存器的值，方便子进程复制
    // 此时父进程还在运行，eip处于LIB_SYSCALL_H lcalll处，等待ret
    // 其tss中esp0没有更新，tss.esp0是进程栈顶初始的地方(比如0)
    // 减去结构体的大小，就获得结构体指针
    syscall_frame_t * syscall_frame = (syscall_frame_t *)(parent_task->tss.esp0 - sizeof(syscall_frame_t)); 
    int err = init_task(child_task, 
                        parent_task->name, 
                        syscall_frame->eip, 
                        syscall_frame->esp + sizeof(uint32_t) * SYSCALL_PARAM_COUNT, 
                        TASK_TYPE_USER);

    copy_opened_file(child_task);
    if(err < 0)
    {
        goto fork_failed;
    }

    tss_t * child_tss = &child_task->tss;
    // 由于子进程需要ret = eax,这里设置为0，给他返回
    child_tss->eax = 0;
    child_tss->ebx = syscall_frame->ebx;
    child_tss->ecx = syscall_frame->ecx;
    child_tss->edx = syscall_frame->edx;
    child_tss->esi = syscall_frame->esi;
    child_tss->edi = syscall_frame->edi;
    child_tss->ebp = syscall_frame->ebp;

    child_tss->cs = syscall_frame->cs;
    child_tss->ds = syscall_frame->ds;
    child_tss->es = syscall_frame->es;
    child_tss->fs = syscall_frame->fs;
    child_tss->gs = syscall_frame->gs;
    child_tss->eflags = syscall_frame->eflags;

    child_task->parent = parent_task;

    if( (child_tss->cr3 = memory_copy_user_linear_mem(parent_task->tss.cr3)) == 0 )
    {
        goto fork_failed;
    }

    task_start(child_task);
    return child_task->pid;

fork_failed:
    if(child_task)
    {
        task_uninit(child_task);
        free_task(child_task);
    }
    return -1;
}

// 从elf_phdr读取信息 加载到page_dir中
static int load_phdr(int file, Elf32_Phdr * elf_phdr, uint32_t page_dir)
{
    int err = memory_alloc_page_for_page_dir(page_dir, 
                                elf_phdr->p_vaddr, 
                                elf_phdr->p_memsz, 
                                PTE_P | PTE_U | PTE_W);
    if (err < 0)
    {
       log_printf("memory_alloc_page_for_page_dir failed");
       return -1;
    }
    
    if(sys_lseek(file, elf_phdr->p_offset, 0) < 0)
    {
        log_printf("read elf phdr's p_offset failed");
        return -1;
    }

    uint32_t vaddr = elf_phdr->p_vaddr;
    uint32_t size = elf_phdr->p_filesz;
    while(size>0)
    {
        int curr_size = (size > MEMORY_PAGE_SIZE) ? MEMORY_PAGE_SIZE : size;
        int paddr = memory_get_pyhscial_addr_from_page_dir(page_dir, vaddr);

        if(sys_read(file, (char *)paddr, curr_size) < curr_size)
        {
            log_printf("read elf phdr from vaddr to paddr failed");
            return -1;
        }

        size -= curr_size;
        vaddr += curr_size;    
    }


}

// 从磁盘上读取进程的elf文件,并为进程分配页表以及页表内存,返回进程的入口
static uint32_t load_elf_file(task_t * task, const char * name, uint32_t page_dir)
{
    Elf32_Ehdr elf_ehdr;
    Elf32_Phdr elf_phdr;
    int file = sys_open(name, 0);
    if(file < 0)
    {
        log_printf("open file failed. %s", name);
        goto load_elf_failed;
    }

    int count = sys_read(file, (char *)&elf_ehdr, sizeof(Elf32_Ehdr));
    if(count < sizeof(Elf32_Ehdr))
    {
        log_printf("elf size too small. size= %d", count);
        goto load_elf_failed;
    }

    if(elf_ehdr.e_ident[0]!=0x7f || elf_ehdr.e_ident[1]!= 'E' || 
        elf_ehdr.e_ident[2]!='L' || elf_ehdr.e_ident[3]!='F')
    {
        log_printf("elf ident check failed.");
        goto load_elf_failed;
    }

    if ((elf_ehdr.e_phentsize == 0) || (elf_ehdr.e_phoff == 0)) {
        log_printf("none programe header");
        goto load_elf_failed;
    }

    // elf表起始地址
    uint32_t e_phoff = elf_ehdr.e_phoff;
    for(int i=0; i<elf_ehdr.e_phnum; i++, e_phoff + sizeof(elf_phdr))
    {
        // 将文件指针移到e_phoff
        if(sys_lseek(file, e_phoff, 0) < 0)
        {
            log_printf("read elf system sleek failed.");
            goto load_elf_failed;
        }

        // 段信息读取到结构体
        count = sys_read(file, (char *)&elf_phdr, sizeof(Elf32_Phdr));
        if(count < sizeof(elf_phdr))
        {
            log_printf("read elf phdr faile.");
            goto load_elf_failed;
        }

        if(elf_phdr.p_type != 1 || elf_phdr.p_vaddr < MEMORY_TASK_BASE)
        {
            continue;
        }

        // 从elf_phdr读取信息 加载到page_dir中
        int err = load_phdr(file, &elf_phdr, page_dir);
        if(err < 0)
        {
            log_printf("load phdr to page dir failed.");
            goto load_elf_failed;
        }

        task->heap_start = elf_phdr.p_vaddr + elf_phdr.p_memsz;
        task->heap_end = task->heap_start;
    }

    sys_close(file);
    return elf_ehdr.e_entry;
load_elf_failed:
    if(file >= 0)
    {
        sys_close(file);
    }

    return 0;
}

// 参数：栈顶指针，栈所在页表，参数数组，参数个数
// 栈中参数应该为 返回地址 参数数量argc 指向字符串数组的指针argv + 各个指针 + 各个字符串 
static int copy_args_to_stack(uint32_t aim_stack, uint32_t new_page_dir, char ** argv, int argc)
{
    task_args_t task_args;
    task_args.argc = argc;
    task_args.argv = (char**)(aim_stack + sizeof(task_args_t));

    // 获取argv这个指针数组的变量的地址 
    // 也是数组中第一个参数的物理地址，也是指向argv[0]的指针的物理地址
    char ** dest_physcial = (char **)memory_get_pyhscial_addr_from_page_dir(new_page_dir, aim_stack + sizeof(task_args_t));
    // 获取argv参数指向的字符串的起始地址,多分配一项,置为0代表结束
    char * dest = (char *)(aim_stack + sizeof(task_args_t) + sizeof(char *) * (argc+1));
    for(int i=0; i<argc; i++)
    {
        char * from = argv[i];
        int len = kernel_strlen(from) + 1;
        int err = memory_copy_user_linear_mem_data((uint32_t)dest, new_page_dir, (uint32_t)from, len);
        ASSERT(err >= 0);
        dest_physcial[i] = dest;    
        dest += len;
    }

    if(argc > 0) dest_physcial[argc] = '\0'; 
     // 拷贝当前页表数据进入其他页表对应的地址
    int err = memory_copy_user_linear_mem_data(aim_stack, 
                                            new_page_dir, 
                                            (uint32_t)&task_args, 
                                            sizeof(task_args));  
    ASSERT(err >= 0);

    return err;
                                
}

int sys_execve(char * name, char ** argv, char ** env)
{
    // 将当前任务替换为新任务
    task_t * curr_task = curr_task_get();
    // 改任务名为新任务名
    kernel_strncpy(curr_task->name, get_file_name_from_path(name), TASK_NAME_SIZE);

    uint32_t old_page_dir = curr_task->tss.cr3;
    uint32_t new_page_dir = memory_create_user_linear_mem();
    if(!new_page_dir)
    {
        goto exec_failed;
    }

    uint32_t new_task_entry = load_elf_file(curr_task, name, new_page_dir);
    if(!new_task_entry)
    {
        goto exec_failed;
    }

    // 新任务的栈顶为MEMORY_TASK_STACK_TOP，保留一些空间给任务运行时所需参数
    uint32_t stack_top = MEMORY_TASK_STACK_TOP - MEMORY_TASK_ARG_SIZE;
    int err = memory_alloc_page_for_page_dir(new_page_dir, 
                                            MEMORY_TASK_STACK_TOP - MEMORY_TASK_STACK_SIZE,
                                            MEMORY_TASK_STACK_SIZE,
                                            PTE_P | PTE_W | PTE_U);
    if(err < 0)
    {
        goto exec_failed;
    }

    // 计算出字符串数组的长度，好压入新任务的栈
    int argc = get_strings_count(argv);
    err = copy_args_to_stack(stack_top, new_page_dir, argv, argc);
    if(err < 0)
    {
        goto exec_failed;
    }

    syscall_frame_t * syscall_frame = (syscall_frame_t *)(curr_task->tss.esp0 - sizeof(syscall_frame_t));
    syscall_frame->eip = new_task_entry;
    syscall_frame->eax = syscall_frame->ebx = syscall_frame->ecx = syscall_frame->edx = 0;
    syscall_frame->esi = syscall_frame->edi = syscall_frame->ebp = 0;
    syscall_frame->eflags = EFLAGS_IF | EFLAGS_ALWAYS_1;
    syscall_frame->esp = stack_top - sizeof(uint32_t) * SYSCALL_PARAM_COUNT;
    curr_task->tss.cr3 = new_page_dir;

    mmu_set_page_dir(new_page_dir);
    memory_free_user_linear_mem(old_page_dir);

    return 0;
exec_failed:
    if(new_page_dir)
    {
        curr_task->tss.cr3 = old_page_dir;
        mmu_set_page_dir(old_page_dir);
        memory_free_user_linear_mem(new_page_dir);
    }
    return -1;  
}


// 为新打开的文件分配文件描述符
int task_alloc_fd(file_t * file)
{
    task_t * task = curr_task_get();
    for(int i=0;i<TASK_OPEN_FILE_MAX;i++)
    {
        file_t * f = task->file_table[i];
        if(!f)
        {
            task->file_table[i] = file;
            return i;
        }
    }
    return -1;
}

void task_free_fd(int fd)
{
    if(fd < 0 || fd>=TASK_OPEN_FILE_MAX)
    {
        return ;
    }
    curr_task_get()->file_table[fd] = 0;
}


// 通过fd获取file
file_t * task_get_file(int fd)
{
    if(fd < 0 || fd >= TASK_OPEN_FILE_MAX)
    {
        log_printf("task get file from fd failed. fd = %d\n", fd);
        return 0;
    }
    file_t * file = curr_task_get()->file_table[fd];
    return file;
}

// 进程退出
void sys_exit(int status)
{
    task_t * curr_task = curr_task_get();
    
    for(int fd=0; fd<TASK_OPEN_FILE_MAX;fd++)
    {
        file_t * file = curr_task->file_table[fd];
        if(file)
        {
            sys_close(fd);
            curr_task->file_table[fd] = 0;
        }
    }

    // 当该进程退出时，移交子进程给first task
    int zombie_child_count = 0;
    mutex_lock(&task_table_mutex);
    for(int i=0; i<OS_TASK_MAX_NUM; i++)
    {
        task_t * task = task_table + i;
        if(task->parent == curr_task)
        {
            task->parent = &task_manager.first_task;
            // 如果当前子进程 也是濒死进程，做标记，以唤醒first_task
            if(task->status == TASK_ZOMBIE)
            {
                zombie_child_count++;
            }
        }
    }
    mutex_unlock(&task_table_mutex);

    irq_status_t irq_status = irq_enter_protection();
    curr_task->running_status = status;
    curr_task->status = TASK_ZOMBIE;

    // 唤醒first_task
    if(zombie_child_count && curr_task->parent != &task_manager.first_task)
    {
        task_set_to_ready(&task_manager.first_task);
    }

    // 唤醒父进程
    if(curr_task->parent->status == TASK_WAITTING)
    {
        task_set_to_ready(curr_task->parent);
    }
    task_remove_ready(curr_task);
    task_manager_update();
    irq_quit_protection(irq_status);
}

// 进程资源回收
int sys_wait(int *status)
{
    task_t * curr_task = curr_task_get();
    // 死循环，必须找到一个濒死进程
    for(;;)
    {
        mutex_lock(&task_table_mutex);
        for(int i=0; i<OS_TASK_MAX_NUM; i++)
        {
            task_t * task = task_table + i;
            if(task->parent != curr_task)
            {
                continue;
            }
            if(task->status == TASK_ZOMBIE)
            {
                int pid = task->pid;
                *status = task->running_status;
                // 释放进程持有资源
                memory_free_user_linear_mem(task->tss.cr3);
                memory_free_page(task->tss.esp0 - MEMORY_PAGE_SIZE);
                kernel_memset(task, 0, sizeof(task_t));
                mutex_unlock(&task_table_mutex);
                return pid;
            }
        }
        mutex_unlock(&task_table_mutex);

        // 查找一次task表,没找到就暂时停止,等待子进程唤醒自己
        irq_status_t irq_status = irq_enter_protection();
        // 父进程等待子进程
        task_remove_ready(curr_task);
        curr_task->status = TASK_WAITTING;
        task_manager_update();
        irq_quit_protection(irq_status);
    }

    return 0;
}